package com.baseproject.datasource.local.file;

import android.content.Context;

import com.anupcowkur.reservoir.ReservoirClearCallback;
import com.anupcowkur.reservoir.ReservoirDeleteCallback;
import com.anupcowkur.reservoir.ReservoirGetCallback;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;

import rx.Observable;

/**
 * Created by hp on 2017/6/14.
 */

public interface ILocalFileStrategy {

    Observable<File> getFile(final String destDir, final String destFileName);

    File saveFile(InputStream is, String path, String fileName);


    /**
     * Initialize Reservoir
     *
     * @param context context.
     * @param maxSize the maximum size in bytes.
     * @throws IOException thrown if the cache cannot be initialized.
     */
    void init(final Context context, final long maxSize) throws IOException;

    /**
     * Check if an object with the given key exists in the Reservoir.
     *
     * @param key the key string.
     * @return true if object with given key exists.
     * @throws IllegalStateException thrown if init method hasn't been called.
     * @throws IOException           thrown if cache cannot be accessed.
     */
    boolean contains(final String key) throws IOException;

    /**
     * Put an object into Reservoir with the given key. This a blocking IO operation. Previously
     * stored object with the same
     * key (if any) will be overwritten.
     *
     * @param key    the key string.
     * @param object the object to be stored.
     * @throws IllegalStateException thrown if init method hasn't been called.
     * @throws IOException           thrown if cache cannot be accessed.
     */
    void put(final String key, final Object object) throws IOException;

    /**
     * Put an object into Reservoir with the given key asynchronously. Previously
     * stored object with the same
     * key (if any) will be overwritten.
     *
     * @param key    the key string.
     * @param object the object to be stored.
     * @return an {@link Observable} that will insert the object into Reservoir. By default, this
     * will be scheduled on a background thread and will be observed on the main thread.
     * @throws IllegalStateException thrown if init method hasn't been called.
     */
    Observable<Boolean> putUsingObservable(final String key, final Object object);

    /**
     * Get an object from Reservoir with the given key. This a blocking IO operation.
     *
     * @param <T>      the type of the object to get.
     * @param key      the key string.
     * @param classOfT the class type of the expected return object.
     * @return the object of the given type if it exists.
     * @throws IllegalStateException thrown if init method hasn't been called.
     * @throws IOException           thrown if cache cannot be accessed.
     */
    <T> T get(final String key, final Class<T> classOfT) throws IOException;

    /**
     * Get an object from Reservoir with the given key. This a blocking IO operation.
     *
     * @param <T>     the type of the object to get.
     * @param key     the key string.
     * @param typeOfT the type of the expected return object.
     * @return the object of the given type if it exists.
     * @throws IllegalStateException thrown if init method hasn't been called.
     * @throws IOException           thrown if cache cannot be accessed.
     */
    <T> T get(final String key, final Type typeOfT) throws IOException;

    /**
     * Get an object from Reservoir with the given key asynchronously.
     *
     * @param <T>      the type of the object to get.
     * @param key      the key string.
     * @param classOfT the class type of the expected return object.
     * @param callback a callback of type {@link com.anupcowkur.reservoir.ReservoirGetCallback}
     *                 which is called upon completion.
     * @throws IllegalStateException thrown if init method hasn't been called.
     */
    <T> void getAsync(final String key, final Class<T> classOfT,
                      final ReservoirGetCallback<T> callback);

    /**
     * Get an object from Reservoir with the given key asynchronously.
     *
     * @param <T>      the type of the object to get.
     * @param key      the key string.
     * @param typeOfT  the type of the expected return object.
     * @param callback a callback of type {@link ReservoirGetCallback}
     *                 which is called upon completion.
     * @throws IllegalStateException thrown if init method hasn't been called.
     */
    <T> void getAsync(final String key, final Type typeOfT,
                      final ReservoirGetCallback<T> callback);

    /**
     * Get an object from Reservoir with the given key asynchronously.
     *
     * @param <T>      the type of the object to get.
     * @param key      the key string.
     * @param classOfT the class type of the expected return object.
     * @return an {@link Observable} that will fetch the object from Reservoir. By default, this
     * will be scheduled on a background thread and will be observed on the main thread.
     * @throws IllegalStateException thrown if init method hasn't been called.
     */
    <T> Observable<T> getUsingObservable(final String key, final Class<T> classOfT);

    /**
     * Get an object from Reservoir with the given key asynchronously.
     *
     * @param <T>      the type of the object to get.
     * @param key      the key string.
     * @param classOfT the class type of the expected return object.
     * @param typeOfT  the type of the collection object which contains objects of type {@code classOfT}.
     * @return an {@link Observable} that will fetch the object from Reservoir. By default, this
     * will be scheduled on a background thread and will be observed on the main thread.
     * @throws IllegalStateException thrown if init method hasn't been called.
     */
    <T> Observable<T> getUsingObservable(final String key, final Class<T> classOfT, final Type typeOfT);

    /**
     * Delete an object from Reservoir with the given key. This a blocking IO operation. Previously
     * stored object with the same
     * key (if any) will be deleted.
     *
     * @param key the key string.
     * @throws IllegalStateException thrown if init method hasn't been called.
     * @throws IOException           thrown if cache cannot be accessed.
     */
    void delete(final String key) throws IOException;

    /**
     * Delete an object into Reservoir with the given key asynchronously. Previously
     * stored object with the same
     * key (if any) will be deleted.
     *
     * @param key      the key string.
     * @param callback a callback of type {@link com.anupcowkur.reservoir.ReservoirDeleteCallback}
     *                 which is called upon completion.
     * @throws IllegalStateException thrown if init method hasn't been called.
     */
    void deleteAsync(final String key, final ReservoirDeleteCallback callback);

    /**
     * Delete an object into Reservoir with the given key asynchronously. Previously
     * stored object with the same
     * key (if any) will be deleted.
     *
     * @param key the key string.
     * @return an {@link Observable} that will delete the object from Reservoir.By default, this
     * will be scheduled on a background thread and will be observed on the main thread.
     * @throws IllegalStateException thrown if init method hasn't been called.
     */
    Observable<Boolean> deleteUsingObservable(final String key);

    /**
     * Clears the cache. Deletes all the stored key-value pairs synchronously.
     *
     * @throws IllegalStateException thrown if init method hasn't been called.
     * @throws IOException           thrown if cache cannot be accessed.
     */
    void clear() throws IOException;

    /**
     * Clears the cache. Deletes all the stored key-value pairs asynchronously.
     *
     * @param callback a callback of type {@link com.anupcowkur.reservoir.ReservoirClearCallback}
     *                 which is called upon completion.
     * @throws IllegalStateException thrown if init method hasn't been called.
     */
    void clearAsync(final ReservoirClearCallback callback);

    /**
     * Clears the cache. Deletes all the stored key-value pairs asynchronously.
     *
     * @return an {@link Observable} that will clear all the key-value pairs from Reservoir.By default, this
     * will be scheduled on a background thread and will be observed on the main thread.
     * @throws IllegalStateException thrown if init method hasn't been called.
     */
    Observable<Boolean> clearUsingObservable();

}
